/**
 * Copyright @2016-present, Sumscope, Inc.
 * All rights reserved.
 */

const router = require('koa-router')();
const fs = require('fs');

class Collector {
  
  constructor() {
    this.mapping = '';
    this.getMapping = [];
    this.postMapping = [];
    this.putMapping = [];
    this.delMapping = [];
  }
  
  get() {
    this._collect(arguments, 2, this.getMapping);
  }
  
  post() {
    this._collect(arguments, 3, this.postMapping);
  }
  
  put() {
    this._collect(arguments, 3, this.putMapping);
  }
  
  del() {
    this._collect(arguments, 3, this.delMapping);
  }
  
  setupRoutes(router, bodyParser) {
    this._setup(router, null, this.getMapping, 'get');
    this._setup(router, bodyParser, this.postMapping, 'post');
    this._setup(router, bodyParser, this.putMapping, 'put');
    this._setup(router, bodyParser, this.delMapping, 'del');
  }
  
  _setup(router, bodyParser, collection, method) {
    collection.forEach(options => {
      let parser = options.parser || bodyParser;
      if (parser) {
        router[method](this.mapping + options.url, parser, options.handler);
      } else {
        router[method](this.mapping + options.url, options.handler);
      }
    })
  }
  
  _collect(parameters, max, collection) {
    if (parameters.length > max) {
      throw new Error(`Invalid arguments for ${parameters[0]}`);
    }
    if (parameters.length === 2) {
      collection.push({url: parameters[0], handler: parameters[1]});
    } else if (parameters.length === 3) {
      collection.push({
        url: parameters[0],
        parser: parameters[1],
        handler: parameters[2]});
    }
  }
}

module.exports = (routeDir, opt) => {
  let routeFiles = fs.readdirSync(routeDir);
  let bodyParser = null;
  if (opt && opt.use) {
    bodyParser = require('koa-bodyparser')(opt);
  }
  routeFiles.filter(file => file !== '.' && file !== '..')
    .forEach(file => {
      const collector = new Collector();
      require(routeDir + '/' + file)(collector);
      collector.setupRoutes(router, bodyParser);
    });
  return router;
};
